﻿using FastMember;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sigil;
using Sigil.NonGeneric;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace TestProject1 {

    [TestClass]
    public class TestReflection {

        private static readonly BindingFlags bflag = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
        private static readonly int num = 10000 * 100;

        /// <summary>
        /// 基础反射方法
        /// </summary>
        [TestMethod]
        public void Test1() {
            TestClass obj = new TestClass("A string");
            dynamic obj2 = obj as dynamic;
            Type type = obj.GetType();
            // 反射字段
            TestUtils.RepeateTest(num, () => {
                FieldInfo fieldInfo = type.GetField("s");
                fieldInfo.GetValue(obj);
                string s =obj2.s;
            },"反射字段");

            // 反射属性
            TestUtils.RepeateTest(num, () => {
                PropertyInfo property = type.GetProperty("Data", bflag);
                property.GetValue(obj, null);
                //Console.WriteLine(property.GetValue(obj, null));
            },"基础测试:");
            PropertyInfo pi = type.GetProperty("Data", bflag);
            TestUtils.RepeateTest(num, () => {
                pi.GetValue(obj, null);
                //Console.WriteLine(property.GetValue(obj, null));
            },"缓存测试:");
            //TypeAccessor accessor = TypeAccessor.Create(type, allowNonPublicAccessors: true);
            //TestUtils.RepeateTest(num, () => {
            //    string s = (string)accessor[obj, "Data"];
            //},"FastMember");
            Func<TestClass, string> getDelegate =
                (Func<TestClass, string>)Delegate
                .CreateDelegate(typeof(Func<TestClass, string>), pi.GetGetMethod(nonPublic: true));
            TestUtils.RepeateTest(num*10, () => {
                getDelegate(obj);
            },"委托测试:");

            // 编译表达式树
            ParameterExpression instance = Expression.Parameter(typeof(object), "instance");
            UnaryExpression instanceCast =
                !pi.DeclaringType.IsValueType ?
                    Expression.TypeAs(instance, pi.DeclaringType):
                    Expression.Convert(instance, pi.DeclaringType);
            Func<object, object> GetDelegate = Expression.Lambda<Func<object, object>>(
                Expression.TypeAs(
                    Expression.Call(instanceCast, pi.GetGetMethod(nonPublic: true))
                    , typeof(object))
                ,instance)
               .Compile();

            TestUtils.RepeateTest(num*10, () => {
                GetDelegate(obj);
            }, "表达树测试:");

            // Emit测试
            Emit<Func<object, string>> getterEmiter = Emit<Func<object, string>>
                .NewDynamicMethod("GetTestClassDataProperty")
                .LoadArgument(0)
                .CastClass(type)
                .Call(pi.GetGetMethod(nonPublic: true)).Return();
            Func<object, string> getter = getterEmiter.CreateDelegate();
            TestUtils.RepeateTest(num * 10, () => {
                getter(obj);
            },"Emit测试");

            TestUtils.RepeateTest(num * 10, () => {
                var a = obj.Data;
            },"直接获取");
        }




        


        public class TestClass {

            public string s="你好";
            private string data;
            public string Data { get { return data; } set { data = value; } }
            public TestClass(String data) {
                Data = data;
            }

            
        }
    }
}
